home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / display.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  39KB  |  1,661 lines

  1. /*
  2.  * $Id: display.c,v 0.91 1994/02/20 00:52:56 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * Display image defined in the image structure. Code is geared for maximum
  26.  * speed. Also, some misc. routines that does mode settting and screen
  27.  * clearing.
  28.  *
  29.  * Area bounded by im->{xi,yi,xf,yf} are the (true) image locations relative to
  30.  * window. In the  case  where the image is larger than window, part of image
  31.  * will be invisible (outside the viewing area). To speed up display, pxi,
  32.  * pyi, pxf, pyf are guaranteed to be within the window even if image is
  33.  * larger than window and degenerates into im->{xi,yi,xf,yf} if image is
  34.  * smaller than window. px0 and py0 indicate the offset into the raster from
  35.  * where the image starts, e.g., if displaying a pixel at  (x,y), image
  36.  * should be starting from  (image + (y+py0) * width + x+px0). The other uses
  37.  * of pxi,pyi etc. are when the image is panned, and part of the image is
  38.  * invisible.
  39.  *
  40.  * The following relation MUST holds for panning etc.
  41.  *
  42.  * im->xf + im->xoff2 - (im->xi + im->xoff2) + 1 == Min(win_w, im->w);
  43.  *
  44.  * Note: for rectwrite, the screen localtions are specified by the parameters
  45.  * and therefore, the x offset equals x-pxi+im->xoff1.
  46.  *
  47.  */
  48. #if !defined(lint) && defined(F_ID)
  49. char *id_dis = "$Id: display.c,v 0.91 1994/02/20 00:52:56 zhao Pre-Release $";
  50. #endif
  51.  
  52. #include "bit.h"
  53. #include "extern.h"
  54. #include "dmalloc.h"
  55.  
  56. /*******************************************************************
  57.  * On some machines (4.0.5H ?), if the image is larger than the physical
  58.  * screen, colormapped image will not display correctly.
  59.  * Define PWRITE_BUG to enable workaround code
  60.  *
  61.  *  To workaround code does not work either, something is wrong
  62.  *  with bit ....
  63.  *******************************************************************/
  64. #define NO_PWRITE_BUG
  65.  
  66. #ifndef NO_PWRITE_BUG
  67. #define PWRITE_BUG
  68. #endif
  69.  
  70. /*****************************************************************
  71.  * Note that ALL windows under BIT process have the same display mode
  72.  * FORM window is not considered to be part of BIT process because
  73.  * it takes care of its own redraws
  74.  *******************************************************************/
  75.  
  76. /********************** Local variables ***************************/
  77.  
  78. static int rgbmode;        /* current window mode         */
  79. static short bkindex = BKINDEX;    /* background color in CI mode */
  80. static rgba_t bkcolor;        /* bkcolor in RGB mode         */
  81. static int bkr, bkg, bkb;    /* r,g,b   for BK              */
  82.  
  83. /********************************************************
  84.  * Set background color, but don't activate
  85.  ********************************************************/
  86.  
  87. void
  88. set_bk_color(rgba_t p)
  89. {
  90.     bkcolor = p;
  91.     CPACK2RGB(p, bkr, bkg, bkb);
  92. }
  93.  
  94. /********************************************************
  95.  * Choose display mode according to image type and hardware
  96.  * characteristics.
  97.  ********************************************************/
  98.  
  99. #include "gl/get.h"
  100.  
  101. /*******************************************************************
  102.  * Switch current display mode to RGB, also matching doublebuffer
  103.  * request.
  104.  ******************************************************************/
  105. void
  106. set_rgb_mode(void)
  107. {
  108.     int mode = getdisplaymode();
  109.  
  110.     /* re-config if mode mismatch or double/single buffer mismtach */
  111.     if (!((mode == DMRGB && !double_buf) ||
  112.       (mode == DMRGBDOUBLE && double_buf)))
  113.       {
  114.  
  115.       M_info("Display", "Switching to RGBmode");
  116.  
  117.       RGBmode();
  118.       (double_buf ? doublebuffer : singlebuffer) ();
  119.       gconfig();
  120.       rgbmode = 1;
  121.       clear_screen(win_id, 1);
  122.       }
  123. }
  124.  
  125. void
  126. set_cmap_mode(void)
  127. {
  128.     int mode = getdisplaymode();
  129.  
  130.     if (!((mode == DMSINGLE && !double_buf) ||
  131.       (mode == DMDOUBLE && double_buf)))
  132.       {
  133.  
  134.       M_info("Display", "Switching to CMAPmode");
  135.  
  136.       cmode();
  137.       (double_buf ? doublebuffer : singlebuffer) ();
  138.       gconfig();
  139.  
  140.       rgbmode = 0;
  141.       clear_screen(win_id, 1);
  142.       }
  143. }
  144.  
  145. void
  146. set_display_mode(IPTR im)
  147. {
  148.     CMPTR map = im->cmap;
  149.  
  150.     set_current_window(win_id);
  151.  
  152.     if (IS_CPACK(im))
  153.       {
  154.       set_rgb_mode();
  155.       }
  156.     else
  157.       {
  158.       set_cmap_mode();
  159.       /* writemask(im->cmap->colors-1); */
  160.       set_cmap(map);
  161.       }
  162.  
  163. }
  164.  
  165. /*********************************************************
  166.  * Clear current window
  167.  *********************************************************/
  168.  
  169. static void
  170. clear_it(void)
  171. {
  172.     if (rgbmode)
  173.     cpack(bkcolor);
  174.     else
  175.       {
  176.       mapcolor(bkindex, bkr, bkg, bkb);
  177.       color(bkindex);
  178.       }
  179.     clear();
  180. }
  181.  
  182. /************************************************************
  183.  * Clear specified window
  184.  ************************************************************/
  185. void
  186. clear_screen(long win, int show)
  187. {
  188.     long owin = winget();
  189.     int dispmode = rgbmode;
  190.  
  191.     set_current_window(win);
  192.     reshapeviewport();
  193.     rgbmode = getdisplaymode();
  194.     rgbmode = (rgbmode == DMRGB || rgbmode == DMRGBDOUBLE);
  195.     clear_it();
  196.     rgbmode = dispmode;
  197.  
  198.     if (show && double_buf)
  199.       {
  200.       swapbuffers();
  201.       clear_it();
  202.       }
  203.  
  204.     set_current_window(owin);
  205.  
  206. }
  207.  
  208. /*****************************************************************
  209.  * Clear the region between rectangle r1 and r2.
  210.  *****************************************************************/
  211. void
  212. clear_between_rect(const Rect_t * r1, const Rect_t * r2)
  213. {
  214.     int xf1 = r1->x + r1->w - 1;
  215.     int yf1 = r1->y + r1->h - 1;
  216.     int xf2 = r2->x + r2->w - 1;
  217.     int yf2 = r2->y + r2->h - 1;
  218.  
  219.     set_color_bk();
  220.  
  221.     /* left */
  222.     if (r1->x > r2->x)
  223.     rectfi(r2->x, r2->y, r1->x - 1, yf2);
  224.  
  225.     /* right */
  226.     if (xf1 < xf2)
  227.     rectfi(xf1 + 1, r2->y, xf2, yf2);
  228.  
  229.     /* bottom */
  230.     if (r1->y > r2->y)
  231.     rectfi(r1->x - 1, r2->y, xf1 + 1, r1->y - 1);
  232.  
  233.     /* top */
  234.     if (yf1 < yf2)
  235.     rectfi(r1->x - 1, yf1 + 1, xf1 + 1, yf2);
  236. }
  237.  
  238. /******************************************************************
  239.  * Clear the regions outside a rectangle and clips at the window
  240.  * boundary. Could be implemented as clear_between_rect.
  241.  ******************************************************************/
  242. void
  243. clear_outside_rect(const Rect_t * r)
  244. {
  245.     int xf = r->x + r->w - 1;
  246.     int yf = r->y + r->h - 1;
  247.  
  248.     set_color_bk();
  249.  
  250.     /* left */
  251.     if (r->x > 0)
  252.     rectfi(0, 0, r->x - 1, win_h - 1);
  253.  
  254.     /* right */
  255.     if (xf < win_w - 1)
  256.     rectfi(xf + 1, 0, win_w - 1, win_h - 1);
  257.  
  258.     /* bottom */
  259.     if (r->y > 0)
  260.     rectfi(r->x - 1, 0, xf + 1, r->y - 1);
  261.  
  262.     /* top */
  263.     if (yf < win_h - 1)
  264.     rectfi(r->x - 1, yf + 1, xf + 1, win_h - 1);
  265. }
  266.  
  267.  
  268. /***************************************************************
  269.  * Set current color.
  270.  ***************************************************************/
  271. void
  272. Color(rgba_t col, int ci)
  273. {
  274.     if (rgbmode)
  275.     cpack(col);
  276.     else
  277.     color(ci);
  278. }
  279.  
  280. /*****************************************************************
  281.  * Color is given as 4 element array: the first three are RGB
  282.  * and the fourth is CI
  283.  ****************************************************************/
  284. void
  285. Color4(int *c)
  286. {
  287.     if (rgbmode)
  288.     cpack(Pack(c[0], c[1], c[2]));
  289.     else
  290.     color(c[3]);
  291. }
  292.  
  293. /***************************************************************
  294.  * activate current background color
  295.  ***************************************************************/
  296. void
  297. set_color_bk(void)
  298. {
  299.     Color(bkcolor, bkindex);
  300. }
  301.  
  302. /*********************************************************
  303.  * Clear a rectanglular region to current bk color
  304.  ********************************************************/
  305. void
  306. rect_clear(long win, int xi, int xf, int yi, int yf)
  307. {
  308.     set_current_window(win);
  309.     viewport(xi, xf, yi, yf);
  310.     clear_it();
  311. }
  312.  
  313. /*********************************************************
  314.  * Pixel blind rectwrite. Should not be called by any of
  315.  * of the displaying related routines, it is meant for
  316.  * subimage handling
  317.  ********************************************************/
  318.  
  319. void
  320. Rectwrite(int xi, int yi, int xf, int yf, void *r)
  321. {
  322.  
  323.     frontbuffer(1);
  324.  
  325.     if (rgbmode)
  326.     lrectwrite(xi, yi, xf, yf, r);
  327.     else
  328.     rectwrite(xi, yi, xf, yf, r);
  329.  
  330.     frontbuffer(!double_buf);
  331.  
  332. }
  333.  
  334. /****************************************************************
  335.  * Pixel type blind framebuffer read
  336.  ***************************************************************/
  337. long
  338. Rectread(int xi, int yi, int xf, int yf, void *r)
  339. {
  340.     return rgbmode ?
  341.     lrectread(xi, yi, xf, yf, r) : rectread(xi, yi, xf, yf, r);
  342. }
  343.  
  344.  
  345. /************************************************************
  346.  * All display related routines, variables
  347.  ************************************************************/
  348.  
  349. static int pxi, pxf, px0, pyi, pyf, py0;
  350. static long xy[2];
  351. static rgba_t **rgba;
  352. static Colorindex **cind;
  353. static float zoomx, zoomy;
  354.  
  355. #define DISP_ROW(y,x1,x2,f,ras)        \
  356.       f(x1,y,x2,y,(ras[y+py0] + (x1 + im->xoff1 - pxi )))
  357.  
  358. /**************************************************************
  359.  * display from top to bottom
  360.  **************************************************************/
  361.  
  362. static void
  363. ds_down(IPTR im)
  364. {
  365.     register int j;
  366.  
  367.     if (IS_CPACK(im))
  368.       {
  369.       for (j = pyf; j >= pyi; j--)
  370.           DISP_ROW(j, pxi, pxf, lrectwrite, rgba);
  371.       }
  372.     else
  373.       {
  374.       for (j = pyf; j >= pyi; j--)
  375.           DISP_ROW(j, pxi, pxf, rectwrite, cind);
  376.       }
  377. }
  378.  
  379. /*************************************************************
  380.  * display from bottom to top
  381.  ************************************************************/
  382.  
  383. static void
  384. ds_up(IPTR im)
  385. {
  386.     register int j;
  387.  
  388.     if (IS_CPACK(im))
  389.       {
  390.       for (j = pyi; j <= pyf; j++)
  391.           DISP_ROW(j, pxi, pxf, lrectwrite, rgba);
  392.       }
  393.     else
  394.       {
  395.       for (j = pyi; j <= pyf; j++)
  396.           DISP_ROW(j, pxi, pxf, rectwrite, cind);
  397.       }
  398. }
  399.  
  400. /************************************************************************
  401.  * Default. Write pixels in one scoop
  402.  ************************************************************************/
  403.  
  404. static void
  405. ds_block(IPTR im)
  406. {
  407.     if (zoomx > 1.1 || zoomy > 1.1)
  408.       {
  409.       if (IS_CPACK(im))
  410.           lrectwrite(im->xi, im->yi, im->xi + im->w - 1,
  411.              im->yi + im->h - 1, rgba[0]);
  412.       else
  413.           rectwrite(im->xi, im->yi, im->xi + im->w - 1,
  414.             im->yi + im->h - 1, cind[0]);
  415.       return;
  416.       }
  417.  
  418.  
  419.     if (IS_CPACK(im))
  420.       {
  421.  
  422.       if (im->w < (win_w + 400) && im->xoff1 < 400 && im->xoff2 < 400)
  423.         {
  424.         lrectwrite(im->xi, pyi, im->xf, pyf, rgba[im->yoff1]);
  425.         }
  426.       else
  427.         {
  428.         ds_up(im);
  429.         }
  430.       return;
  431.       }
  432.  
  433.     /* must be CI and need to take care of the bug */
  434.  
  435. #ifdef PWRITE_BUG
  436.     if ((im->xi + win_xo) > 0 && im->xf < getgdesc(GD_XPMAX))
  437. #else
  438.     if (im->w < (win_w + 400) && im->xoff1 < 400 && im->xoff2 < 400)
  439. #endif
  440.       {
  441.       rectwrite(im->xi, pyi, im->xf, pyf, cind[im->yoff1]);
  442.       }
  443.     else
  444.       {
  445.       ds_up(im);
  446.       }
  447.  
  448. }
  449.  
  450. /************************************************************
  451.  * explode from center to top and bottom
  452.  **************************************************************/
  453.  
  454. static void
  455. ds_ctb(IPTR im)
  456. {
  457.     register int j, hh = (pyf - pyi + 1) / 2, cc = (pyf + pyi) / 2;
  458.  
  459.     if (IS_CPACK(im))
  460.       {
  461.       for (j = 0; j <= hh; j++)
  462.         {
  463.         if (cc - j >= pyi)
  464.             DISP_ROW(cc - j, pxi, pxf, lrectwrite, rgba);
  465.         if (cc + j <= pyf)
  466.             DISP_ROW(cc + j, pxi, pxf, lrectwrite, rgba);
  467.         }
  468.       }
  469.     else
  470.       {
  471.       for (j = 0; j <= hh; j++)
  472.         {
  473.         if (cc - j >= pyi)
  474.             DISP_ROW(cc - j, pxi, pxf, rectwrite, cind);
  475.         if (cc + j <= pyf)
  476.             DISP_ROW(cc + j, pxi, pxf, rectwrite, cind);
  477.         }
  478.       }
  479. }
  480.  
  481. /******************************************************************
  482.  * explode from top and bottom towards the center line
  483.  ******************************************************************/
  484.  
  485. static void
  486. ds_tbc(IPTR im)
  487. {
  488.     register int j, hh = (pyf - pyi + 1) / 2;
  489.  
  490.     if (IS_CPACK(im))
  491.       {
  492.       for (j = 0; j <= hh; j++)
  493.         {
  494.         DISP_ROW(pyi + j, pxi, pxf, lrectwrite, rgba);
  495.         DISP_ROW(pyf - j, pxi, pxf, lrectwrite, rgba);
  496.         }
  497.       }
  498.     else
  499.       {
  500.       for (j = 0; j <= hh; j++)
  501.         {
  502.         DISP_ROW(pyi + j, pxi, pxf, rectwrite, cind);
  503.         DISP_ROW(pyf - j, pxi, pxf, rectwrite, cind);
  504.         }
  505.       }
  506. }
  507.  
  508. #define DN_RSEG(y1,y2,s,f,ras)                                     \
  509.              do {                                                  \
  510.                for (i=y1;i>=y2;i-=s) { DISP_ROW(i,pxi,pxf,f,ras);} \
  511.              } while (ZERO)
  512.  
  513. /**********************************************************
  514.  * GIF interlace
  515.  **********************************************************/
  516. static void
  517. ds_gint(IPTR im)
  518. {
  519.     register int i;
  520.  
  521.     if (IS_CPACK(im))
  522.       {
  523.       DN_RSEG(pyf, pyi, 8, lrectwrite, rgba);
  524.       DN_RSEG(pyf - 4, pyi, 8, lrectwrite, rgba);
  525.       DN_RSEG(pyf - 2, pyi, 4, lrectwrite, rgba);
  526.       DN_RSEG(pyf - 1, pyi, 2, lrectwrite, rgba);
  527.       }
  528.     else
  529.       {
  530.       DN_RSEG(pyf, pyi, 8, rectwrite, cind);
  531.       DN_RSEG(pyf - 4, pyi, 8, rectwrite, cind);
  532.       DN_RSEG(pyf - 2, pyi, 4, rectwrite, cind);
  533.       DN_RSEG(pyf - 1, pyi, 2, rectwrite, cind);
  534.       }
  535. }
  536.  
  537. /*************************************************************
  538.  * nice interlace
  539.  *************************************************************/
  540.  
  541. static void
  542. ds_int(IPTR im)
  543. {
  544.     register int i;
  545.  
  546.     if (IS_CPACK(im))
  547.       {
  548.       DN_RSEG(pyf, pyi, 4, lrectwrite, rgba);
  549.       DN_RSEG(pyf - 2, pyi, 4, lrectwrite, rgba);
  550.       DN_RSEG(pyf - 3, pyi, 4, lrectwrite, rgba);
  551.       DN_RSEG(pyf - 1, pyi, 4, lrectwrite, rgba);
  552.       }
  553.     else
  554.       {
  555.       DN_RSEG(pyf, pyi, 4, rectwrite, cind);
  556.       DN_RSEG(pyf - 2, pyi, 4, rectwrite, cind);
  557.       DN_RSEG(pyf - 3, pyi, 4, rectwrite, cind);
  558.       DN_RSEG(pyf - 1, pyi, 4, rectwrite, cind);
  559.       }
  560. }
  561.  
  562.  
  563. #define DISP_COL(x,y1,y2,f,ras)                                      \
  564.         do {                                                         \
  565.            register int k_, xx_;                                     \
  566.            xy[0]= x; xx_= x + px0;                                   \
  567.            for (k_ = y1; k_ <= y2; ++k_) {                           \
  568.                xy[1]= k_; f(ras[k_+py0][xx_]); v2i(xy);              \
  569.            }                                                         \
  570.         } while (ZERO)
  571.  
  572.  
  573.  
  574. /*****************************************************************
  575.  * display from left to right
  576.  *****************************************************************/
  577.  
  578. static void
  579. ds_left(IPTR im)
  580. {
  581.     register int i;
  582.  
  583.     bgnpoint();
  584.  
  585.     if (IS_CPACK(im))
  586.       {
  587.       for (i = pxi; i <= pxf; i++)
  588.           DISP_COL(i, pyi, pyf, cpack, rgba);
  589.       }
  590.     else
  591.       {
  592.       for (i = pxi; i <= pxf; i++)
  593.           DISP_COL(i, pyi, pyf, color, cind);
  594.       }
  595.  
  596.     endpoint();
  597. }
  598.  
  599. /***************************************************************
  600.  * Display from right to left
  601.  ***************************************************************/
  602.  
  603. static void
  604. ds_right(IPTR im)
  605. {
  606.     register int i;
  607.  
  608.     bgnpoint();
  609.  
  610.     if (IS_CPACK(im))
  611.       {
  612.       for (i = pxf; i >= pxi; i--)
  613.           DISP_COL(i, pyi, pyf, cpack, rgba);
  614.       }
  615.     else
  616.       {
  617.       for (i = pxf; i >= pxi; i--)
  618.           DISP_COL(i, pyi, pyf, color, cind);
  619.       }
  620.  
  621.     endpoint();
  622. }
  623.  
  624. #define LR_CSEG(x1,x2,s,f,ras)                              \
  625.          for ( i= x1; i<= x2; i += s)                   \
  626.                       DISP_COL(i,pyi,pyf,f,ras)
  627.  
  628.  
  629. /*****************************************************************
  630.  * columnwise interlace
  631.  ******************************************************************/
  632.  
  633. static void
  634. ds_cint(IPTR im)
  635. {
  636.     register int i;
  637.  
  638.     bgnpoint();
  639.  
  640.     if (IS_CPACK(im))
  641.       {
  642.       LR_CSEG(pxi, pxf, 4, cpack, rgba);
  643.       LR_CSEG(pxi + 2, pxf, 4, cpack, rgba);
  644.       LR_CSEG(pxi + 1, pxf, 4, cpack, rgba);
  645.       LR_CSEG(pxi + 3, pxf, 4, cpack, rgba);
  646.       }
  647.     else
  648.       {
  649.       LR_CSEG(pxi, pxf, 4, color, cind);
  650.       LR_CSEG(pxi + 2, pxf, 4, color, cind);
  651.       LR_CSEG(pxi + 1, pxf, 4, color, cind);
  652.       LR_CSEG(pxi + 3, pxf, 4, color, cind);
  653.       }
  654.  
  655.     endpoint();
  656. }
  657.  
  658. /***********************************************************
  659.  * explode leftright from center
  660.  ************************************************************/
  661.  
  662. static void
  663. ds_clr(IPTR im)
  664. {
  665.     register int i, ww = (pxf - pxi + 1) / 2, cc = (pxf + pxi) / 2;
  666.  
  667.     bgnpoint();
  668.  
  669.     if (IS_CPACK(im))
  670.       {
  671.       for (i = 0; i <= ww; i++)
  672.         {
  673.         if (cc - i >= pxi)
  674.             DISP_COL(cc - i, pyi, pyf, cpack, rgba);
  675.         if (cc + i <= pxf)
  676.             DISP_COL(cc + i, pyi, pyf, cpack, rgba);
  677.         }
  678.       }
  679.     else
  680.       {
  681.       for (i = 0; i <= ww; i++)
  682.         {
  683.         if (cc - i >= pxi)
  684.             DISP_COL(cc - i, pyi, pyf, color, cind);
  685.         if (cc + i <= pxf)
  686.             DISP_COL(cc + i, pyi, pyf, color, cind);
  687.         }
  688.       }
  689.  
  690.     endpoint();
  691. }
  692.  
  693. /************************************************************
  694.  * explode left right towards the center
  695.  ************************************************************/
  696.  
  697. static void
  698. ds_lrc(IPTR im)
  699. {
  700.     register int i, ww = (pxf - pxi + 1) / 2;
  701.  
  702.     bgnpoint();
  703.  
  704.     if (IS_CPACK(im))
  705.       {
  706.       for (i = 0; i <= ww; i++)
  707.         {
  708.         DISP_COL(pxi + i, pyi, pyf, cpack, rgba);
  709.         DISP_COL(pxf - i, pyi, pyf, cpack, rgba);
  710.         }
  711.       }
  712.     else
  713.       {
  714.       for (i = 0; i <= ww; i++)
  715.         {
  716.         DISP_COL(pxi + i, pyi, pyf, color, cind);
  717.         DISP_COL(pxf - i, pyi, pyf, color, cind);
  718.         }
  719.       }
  720.  
  721.     endpoint();
  722. }
  723.  
  724. /* macros that displays rectangularly towards the center */
  725. #define RDISP_RECT(x1,y1,x2,y2,rf,cf,ras)                         \
  726.       do {                                                        \
  727.          DISP_ROW(y1,x1,x2,rf,ras);                               \
  728.          DISP_ROW(y2,x1,x2,rf,ras);                               \
  729.          bgnpoint();                                              \
  730.          DISP_COL(x1,y1,y2,cf,ras);                               \
  731.          DISP_COL(x2,y1,y2,cf,ras);                               \
  732.          endpoint();                                              \
  733.       } while (ZERO)
  734.  
  735.  
  736. /*****************************************************************
  737.  * Display rectangularly
  738.  *****************************************************************/
  739.  
  740. static void
  741. ds_rec1(IPTR im)
  742. {
  743.     register int m = 0, hh = (pyf - pyi + 1) / 2, ww = (pxf - pxi + 1) / 2;
  744.     register int xx1 = pxi, xx2 = pxf, yy1 = pyi, yy2 = pyf;
  745.  
  746.     if (IS_CPACK(im))
  747.       {
  748.       do
  749.         {
  750.         RDISP_RECT(xx1, yy1, xx2, yy2, lrectwrite, cpack, rgba);
  751.         xx1++;
  752.         yy1++;
  753.         xx2--;
  754.         yy2--;
  755.         m++;
  756.         }
  757.       while (m <= hh || m <= ww);
  758.       }
  759.     else
  760.       {
  761.       do
  762.         {
  763.         RDISP_RECT(xx1, yy1, xx2, yy2, rectwrite, color, cind);
  764.         xx1++;
  765.         yy1++;
  766.         xx2--;
  767.         yy2--;
  768.         m++;
  769.         }
  770.       while (m <= hh || m <= ww);
  771.       }
  772. }
  773.  
  774. /*************************************************************
  775.  * display rectangularly from the center
  776.  **************************************************************/
  777.  
  778. static void
  779. ds_rec2(IPTR im)
  780. {
  781.     int ch = (pyf + pyi) / 2, cw = (pxf + pxi) / 2;
  782.     register int m = 0, hh = (pyf - pyi + 1) / 2, ww = (pxf - pxi + 1) / 2;
  783.     register int xx1 = cw, xx2 = cw, yy1 = ch, yy2 = ch;
  784.  
  785.     if (IS_CPACK(im))
  786.       {
  787.       do
  788.         {
  789.         RDISP_RECT(xx1, yy1, xx2, yy2, lrectwrite, cpack, rgba);
  790.         xx1 = (xx1 <= pxi) ? pxi : xx1 - 1;
  791.         yy1 = (yy1 <= pyi) ? pyi : yy1 - 1;
  792.         xx2 = (xx2 >= pxf) ? pxf : xx2 + 1;
  793.         yy2 = (yy2 >= pyf) ? pyf : yy2 + 1;
  794.         m++;
  795.         }
  796.       while (m <= hh || m <= ww);
  797.       }
  798.     else
  799.       {
  800.       do
  801.         {
  802.         RDISP_RECT(xx1, yy1, xx2, yy2, rectwrite, color, cind);
  803.         xx1 = (xx1 <= pxi) ? pxi : xx1 - 1;
  804.         yy1 = (yy1 <= pyi) ? pyi : yy1 - 1;
  805.         xx2 = (xx2 >= pxf) ? pxf : xx2 + 1;
  806.         yy2 = (yy2 >= pyf) ? pyf : yy2 + 1;
  807.         m++;
  808.         }
  809.       while (m <= hh || m <= ww);
  810.       }
  811. }
  812.  
  813. /************************************************************
  814.  * blend two streams: c = s * a + ( 1 - s) * b
  815.  ***********************************************************/
  816.  
  817. static int blend_buf[2 * PCMAX + 3];
  818.  
  819. static void
  820. blend_mat(register rgba_t *c, register rgba_t *a, register rgba_t *b,
  821.       register long total, register float s)
  822. {
  823.     register int r1, g1, b1;
  824.     register int r2, g2, b2;
  825.     register int r3, g3, b3;
  826.     register rgba_t *cs;
  827.     register int *lut = blend_buf;
  828.     int i;
  829.  
  830.     /* calculate the lookup table */
  831.  
  832.     lut += PCMAXV;
  833.     for (i = -PCMAXV; i < PCMAX; i++)
  834.     lut[i] = (s * i);
  835.  
  836.     /* blend */
  837.     for (cs = c + total; c < cs; c++, a++, b++)
  838.       {
  839.       Unpack(*a, r1, g1, b1);
  840.       Unpack(*b, r2, g2, b2);
  841.       r3 = *(lut + r1 - r2) + r2;
  842.       g3 = *(lut + g1 - g2) + g2;
  843.       b3 = *(lut + b1 - b2) + b2;
  844.       *c = Pack(r3, g3, b3);
  845.       }
  846. }
  847.  
  848. /****************************************************************
  849.  * slowly fade into new picture
  850.  ****************************************************************/
  851.  
  852. static void
  853. ds_fade(IPTR im)
  854. {
  855.     rgba_t **old, **new, **blend;
  856.     int nstep = 25;
  857.     float f, df;
  858.     const Rect_t *ir, *wr, *ur;
  859.  
  860.     /* fade can only be done to RGB images */
  861.     if (IS_CI(im))
  862.       {
  863.       ds_block(im);
  864.       return;
  865.       }
  866.  
  867.     /* find the dimension of exposed part of the image  */
  868.     wr = make_rect(0, 0, win_w - 1, win_h - 1);
  869.     ur = union_rect(ir = img_rect(im), wr);
  870.  
  871.  
  872.     /* grab all the memory we needed before proceed */
  873.  
  874.     if (!(old = get_mat(ur->h, ur->w, sizeof(rgba_t))))
  875.       {
  876.       ds_block(im);
  877.       return;
  878.       }
  879.  
  880.  
  881.     /* get the current image on screen */
  882.     lrectread(ur->x, ur->y, ur->x + ur->w - 1, ur->y + ur->h - 1, old[0]);
  883.  
  884.     /*
  885.      * matrix for new image: if the new image is completely exposed, no need
  886.      * to allocate a matrix for the exposed part
  887.      */
  888.     new = (equal_rect(ir, ur) ? im->mraster :
  889.        get_subimage(im, ur->x, ur->y, ur->w, ur->h));
  890.  
  891.     if (!new)
  892.       {
  893.       ds_block(im);
  894.       return;
  895.       }
  896.  
  897.     blend = get_mat(ur->h, ur->w, sizeof(rgba_t));
  898.  
  899.     /* adjust steps: if image is large, decrease nstep, otherwise too slow */
  900.  
  901.     nstep = (1600.0 / (im->h + im->w) * nstep);
  902.  
  903.     df = 1.0 / nstep;
  904.  
  905.  
  906.     /* write the first (0) blend immediately, looks faster */
  907.     set_current_window(win_id);
  908.     clear_outside_rect(ur);
  909.     lrectwrite(ur->x, ur->y, ur->x + ur->w - 1, ur->y + ur->h - 1, old[0]);
  910.     frontbuffer(0);
  911.  
  912.     /* simply blend the two images: b = a * old + (1-a) * new */
  913.     for (f = 1.0 - df; f >= 0.0; f -= df)
  914.       {
  915.       blend_mat(blend[0], old[0], new[0], ur->w * ur->h, f);
  916.       lrectwrite(ur->x, ur->y,
  917.              ur->x + ur->w - 1, ur->y + ur->h - 1, blend[0]);
  918.       swapbuffers();
  919.       check_emergency();
  920.       }
  921.  
  922.     /*
  923.      * need to do this to show the complete pictures as blending might have
  924.      * errors due to floating point operation
  925.      */
  926.  
  927.     ds_block(im);
  928.  
  929.     free_mat(blend);
  930.     free_mat(old);
  931.  
  932.     if (new != im->mraster)
  933.     free_mat(new);
  934. }
  935.  
  936. /************************************************************
  937.  * Spark fade
  938.  ***********************************************************/
  939.  
  940. static short *msparkle;
  941. static int max_sp;
  942.  
  943. /** Load sparkle data. should generate this on the fly .... ***/
  944. static int
  945. load_sparkle(void)
  946. {
  947.     FILE *fp = get_HELPfile_fp("sparkle.dat", "r");
  948.     int mm;
  949.     short aa;
  950.     static int warned;
  951.  
  952.     if (!fp)
  953.       {
  954.       if (!warned)
  955.         {
  956.         Bark("LoadSPData", "BadOpen");
  957.         warned = 1;
  958.         }
  959.       return -1;
  960.       }
  961.  
  962.     fread(&aa, sizeof(short), 1, fp);
  963.     max_sp = aa;
  964.     mm = max_sp * max_sp;
  965.     msparkle = malloc(sizeof(short) * (mm + 1));
  966.     fread(msparkle, sizeof(short), mm, fp);
  967.     (void) fclose(fp);
  968.     return 0;
  969. }
  970.  
  971. /************************************************************
  972.  * Actually do the sparkle fade
  973.  ************************************************************/
  974.  
  975. static void
  976. ds_sprkl(IPTR im)
  977. {
  978.     static int first = 1;
  979.     register int cellx, celly;
  980.     register int i1, j1, xx1, xx2, yy1, yy2;
  981.     register int i;
  982.  
  983.     if (first)
  984.     first = load_sparkle();
  985.  
  986.     if (first || !msparkle)
  987.       {
  988.       ds_block(im);
  989.       return;
  990.       }
  991.  
  992.     cellx = im->w / max_sp + ((im->w % max_sp) != 0);
  993.     celly = im->h / max_sp + ((im->h % max_sp) != 0);
  994.  
  995.     for (i = 0; i < (max_sp * max_sp); i++)
  996.       {
  997.       i1 = msparkle[i] / max_sp;
  998.       j1 = msparkle[i] % max_sp;
  999.       xx1 = im->xi + i1 * cellx;
  1000.       yy1 = im->yi + j1 * celly;
  1001.       xx2 = xx1 + cellx;
  1002.       yy2 = yy1 + celly;
  1003.       if (xx2 > im->xf)
  1004.           xx2 = im->xf;
  1005.       if (yy2 > im->yf)
  1006.           yy2 = im->yf;
  1007.       if (xx2 > xx1 && yy2 > yy1)
  1008.           draw_subimage(im, xx1, yy1, xx2 - xx1 + 1, yy2 - yy1 + 1);
  1009.       }
  1010. }
  1011.  
  1012. /******************************************************************
  1013.  * If image is larger than screen or its position not conform to the
  1014.  * positioning requirememt, this routine will be called.
  1015.  *****************************************************************/
  1016.  
  1017. static void
  1018. positioning_image(IPTR im)
  1019. {
  1020.  
  1021.     im->xoff1 = (im->xi < 0) ? -im->xi : 0;
  1022.     im->xoff2 = (im->xf > win_w) ? (win_w - im->xf - 1) : 0;
  1023.     im->yoff1 = (im->yi < 0) ? -im->yi : 0;
  1024.     im->yoff2 = (im->yf > win_h) ? (win_h - im->yf - 1) : 0;
  1025.  
  1026. #ifdef MTRACE
  1027.     M_trace("PosImg", "xoff1=%d yoff1=%d", im->xoff1, im->yoff1);
  1028. #endif
  1029. }
  1030.  
  1031. /************* checks if position is ok ****************************/
  1032.  
  1033. static int
  1034. bad_position(IPTR im)
  1035. {
  1036.  
  1037.     return ((im->xoff1 != 0 && (im->xoff1 + im->xi) != 0) ||
  1038.         (im->yoff1 != 0 && (im->yoff1 + im->yi) != 0) ||
  1039.         (im->xoff2 != 0 && (im->xoff2 + im->xf) != win_w - 1) ||
  1040.         (im->yoff2 != 0 && (im->yoff2 + im->yf) != win_h - 1));
  1041. }
  1042.  
  1043. /*****************************************************************
  1044.  * the global display function interface
  1045.  *
  1046.  *****************************************************************/
  1047. typedef enum
  1048. {
  1049.     DS_INVALID = -1,        /* forcing type to be of a signed type */
  1050.     DS_BLOCK,
  1051.     DS_DOWN,
  1052.     DS_UP,
  1053.     DS_LEFT,
  1054.     DS_RIGHT,
  1055.     DS_TBC,
  1056.     DS_CTB,
  1057.     DS_LRC,
  1058.     DS_CLR,
  1059.     DS_INT,
  1060.     DS_CINT,
  1061.     DS_GINT,
  1062.     DS_REC1,
  1063.     DS_REC2,
  1064.     DS_SPRKL,
  1065.     DS_FADE,
  1066.     DS_CYC            /* special: cyclr thru all of above */
  1067. } DS_MODE;
  1068.  
  1069. typedef struct
  1070.   {
  1071.       DS_MODE ds;
  1072.       void (*dsfunc) (IPTR);
  1073.   }
  1074. Disp;
  1075.  
  1076. static Disp disp[] =
  1077. {
  1078.     {DS_BLOCK, ds_block},
  1079.     {DS_DOWN, ds_down},
  1080.     {DS_UP, ds_up},
  1081.     {DS_LEFT, ds_left},
  1082.     {DS_RIGHT, ds_right},
  1083.     {DS_TBC, ds_tbc},
  1084.     {DS_CTB, ds_ctb},
  1085.     {DS_LRC, ds_lrc},
  1086.     {DS_CLR, ds_clr},
  1087.     {DS_INT, ds_int},
  1088.     {DS_CINT, ds_cint},
  1089.     {DS_GINT, ds_gint},
  1090.     {DS_REC1, ds_rec1},
  1091.     {DS_REC2, ds_rec2},
  1092.     {DS_SPRKL, ds_sprkl},
  1093.     {DS_FADE, ds_fade}
  1094. };
  1095.  
  1096. static int ndisp = sizeof(disp) / sizeof(disp[0]);
  1097.  
  1098. /****** funciton generates the option string *******/
  1099. const char *
  1100. gds_string(void)
  1101. {
  1102.     return "Block|Down|Up|Left|Right|DownUp|UpDown|LR|RL|Int|CInt|"
  1103.     "GInt|Rec1|Rec2|Sparkle|Fade|Cycle";
  1104. }
  1105.  
  1106. /******************************************************************
  1107.  * Display the image defined in the IPTR structure
  1108.  *****************************************************************/
  1109.  
  1110. static void
  1111. set_display_zoom(IPTR im)
  1112. {
  1113.  
  1114.     if (g_zoomx < 0.1 || g_zoomy < 0.1)
  1115.       {
  1116.       zoomx = ((win_w + 100) / im->w);
  1117.       zoomy = ((win_h + 100) / im->h);
  1118.       zoomx = zoomy = Min(zoomx, zoomy);
  1119.       if (zoomx < 0.1)
  1120.           zoomx = zoomy = 1.0;
  1121.       }
  1122.     else
  1123.       {
  1124.       zoomx = g_zoomx;
  1125.       zoomy = g_zoomy;
  1126.       }
  1127. }
  1128.  
  1129. static int display_auto;    /* so we can turn buy cursor off */
  1130. static int dstyle;
  1131.  
  1132. static void
  1133. refresh_display(IPTR i)
  1134. {
  1135.  
  1136.     if (dstyle != DS_FADE && (double_buf || (win_h > i->h || win_w > i->w)))
  1137.     clear_outside_rect(img_rect(i));
  1138. }
  1139.  
  1140. void
  1141. display_image(IPTR im, int ds_fancy, int pre_clean)
  1142. {
  1143.     int ldstyle = ds_fancy;
  1144.  
  1145.     if (!image_ready(im, "Display"))
  1146.     return;
  1147.  
  1148.     if (!display_auto)
  1149.     show_busy("");
  1150.  
  1151. #ifdef MDEBUG
  1152.     M_debug("DisplayImage", "Setting Mode");
  1153. #endif
  1154.  
  1155.  
  1156.     if (ldstyle < 0 || ldstyle >= ndisp)
  1157.     ldstyle = DS_BLOCK;
  1158.  
  1159.     dstyle = ldstyle;        /* center image uses dstyle */
  1160.  
  1161.     /* Initialize CI&RGBA matrix */
  1162.     rgba = im->mraster;
  1163.     cind = im->mraster;
  1164.  
  1165.     set_current_window(win_id);
  1166.     reshapeviewport();
  1167.     set_display_mode(im);
  1168.     set_display_zoom(im);
  1169.  
  1170.     /* If not centered , center it. */
  1171.  
  1172.     if (im->w != (im->xf - im->xi + 1) || im->h != (im->yf - im->yi + 1))
  1173.       {
  1174.       update_image_info(im);
  1175.       center_image(im, 2);
  1176.       M_info("DisplayImage", "Centering Image");
  1177.       }
  1178.  
  1179.     if (bad_position(im))
  1180.     positioning_image(im);
  1181.  
  1182.     /*
  1183.      * avoid repaint screen if possible, also if the display style is fade,
  1184.      * must not clear screen
  1185.      */
  1186.  
  1187.     M_info("DisplayImage", "Clearing Display");
  1188.  
  1189.     if (pre_clean)
  1190.     refresh_display(im);
  1191.  
  1192.  
  1193.     pxi = im->xi + im->xoff1;
  1194.     pxf = im->xf + im->xoff2;
  1195.     px0 = -im->xi;
  1196.     pyi = im->yi + im->yoff1;
  1197.     pyf = im->yf + im->yoff2;
  1198.     py0 = -im->yi;
  1199.  
  1200.     set_current_window(win_id);
  1201.     reshapeviewport();
  1202.  
  1203.     if (dstyle == DS_BLOCK)
  1204.       {
  1205.       rectzoom(zoomx, zoomy);
  1206.       }
  1207.     else
  1208.       {
  1209.       swapbuffers();    /* show last clear_outside_rect */
  1210.       refresh_display(im);
  1211.       frontbuffer(1);
  1212.       rectzoom(1.0, 1.0);
  1213.       }
  1214.  
  1215. #ifdef MDEBUG
  1216.     M_debug("DisplayImage", "Displaying with style=%d", (int) ldstyle);
  1217. #endif
  1218.  
  1219.     (disp + ldstyle)->dsfunc(im);
  1220.  
  1221.     end_busy();
  1222.  
  1223.     frontbuffer(!double_buf);
  1224.  
  1225. }
  1226.  
  1227. /******************************************************************
  1228.  * Similar to display_image but addtionally display text and
  1229.  * other misc. stuff. Also the default display function
  1230.  ******************************************************************/
  1231.  
  1232. void
  1233. Generic_display(IPTR im, int ds_fancy, int pre_clean)
  1234. {
  1235.     static int lfancy;        /* counter. Dstyle is the current style */
  1236.     long owin = winget();
  1237.  
  1238.     /*
  1239.      * it is possible that main window is not initialized if fit_image_size
  1240.      * is requested
  1241.      */
  1242.  
  1243.     open_main_window(im);
  1244.  
  1245. #ifdef MTRACE
  1246.     M_trace("GenericDisplay", "Entering with ds_fancy=%d", ds_fancy);
  1247. #endif
  1248.  
  1249.     if (ds_fancy >= ndisp)
  1250.     ds_fancy = DS_CYC;
  1251.  
  1252.     dstyle = (ds_fancy == DS_CYC) ? (++lfancy % ndisp) : ds_fancy;
  1253.  
  1254.     /* interlace only if image is interlaced and not repaint (-1) */
  1255.     if (im->interlace && ds_fancy >= 0)
  1256.     dstyle = DS_GINT;
  1257.  
  1258.     display_image(im, dstyle, pre_clean);
  1259.     display_sgf(im);
  1260.     display_text(im);
  1261.  
  1262.     /*
  1263.      * if ds_fancy > 0, frontbuffer & backbuffer already consistent as
  1264.      * display_image turned frontbuffer true
  1265.      */
  1266.  
  1267.     if (double_buf && dstyle <= 0)
  1268.       {
  1269.       swapbuffers();
  1270.  
  1271.       /*
  1272.        * in slideshow mode, we do not need to guarantee backbuffer
  1273.        * consistency, which is relied upon in Text, C&P only.
  1274.        */
  1275.  
  1276.       if (!slideshow)
  1277.         {
  1278.         display_auto = 1;
  1279.         display_image(im, DS_BLOCK, pre_clean);
  1280.         display_sgf(im);
  1281.         display_text(im);
  1282.         display_auto = 0;
  1283.         }
  1284.       }
  1285.  
  1286.     set_current_window(owin);
  1287.  
  1288. #ifdef MTRACE
  1289.     M_trace("GenericDisplay", "Exiting");
  1290. #endif
  1291. }
  1292.  
  1293.  
  1294. /************************************************************************
  1295.  * xoff and yoff makes displaying large image a little faster. Note
  1296.  * im->xf+im->xoff2 - im->xi+im->xoff1 + 1== im->w>win_w?win_w:im->w;
  1297.  *
  1298.  * xdir:0 for y direction 1 for x direction 3 for both
  1299.  ************************************************************************/
  1300.  
  1301. void
  1302. center_image(IPTR im, int xdir)
  1303. {
  1304.     int w = im->w, h = im->h;
  1305.  
  1306.     if (dstyle == DS_BLOCK)
  1307.       {
  1308.       w *= zoomx;
  1309.       h *= zoomy;
  1310.       }
  1311.  
  1312.     if (xdir)
  1313.       {
  1314.       im->xi = (win_w - w) / 2;
  1315.  
  1316. #ifdef PWRITE_BUG
  1317.       if ((im->xi + win_xo) <= 0)
  1318.           im->xi = -win_xo + 1;
  1319. #endif
  1320.       im->xf = im->xi + w - 1;
  1321.       }
  1322.  
  1323.     if (xdir == 2 || xdir == 0)
  1324.       {
  1325.       im->yi = (win_h - h) / 2;
  1326.       im->yf = im->yi + h - 1;
  1327.       }
  1328.  
  1329. #ifdef MDEBUG
  1330.     M_debug("CenterImage", "xi=%d yi=%d", im->xi, im->yi);
  1331. #endif
  1332.  
  1333.     positioning_image(im);
  1334. }
  1335.  
  1336. /********************************************************************
  1337.  * Pan iamge so that the viewing area is not limited by the screen size.
  1338.  * Code is so written to minimize the repaint if single buffer is used.
  1339.  ********************************************************************/
  1340.  
  1341. /*
  1342.  * the buttons are numbered  as the keypad
  1343.  */
  1344. int
  1345. image_pan(IPTR im, int x, int pstep)
  1346. {
  1347.     int xvi[2], xvf[2], yvi[2], yvf[2];
  1348.     int nc = 1;
  1349.     int xi, xf, yi, yf;
  1350.     static int last_center, min_keep = 100;
  1351.  
  1352.     /*
  1353.      * if image not ready, should be silently ignored because the pan button
  1354.      * is a touch button
  1355.      */
  1356.  
  1357.     if (!im->ok)
  1358.     return -1;
  1359.  
  1360.  
  1361.     xi = xvi[0] = xvi[1] = im->xi;
  1362.     xf = xvf[0] = xvf[1] = im->xf;
  1363.     yi = yvi[0] = yvi[1] = im->yi;
  1364.     yf = yvf[0] = yvf[1] = im->yf;
  1365.  
  1366.     switch (x)
  1367.       {
  1368.       case 1:            /* left-down */
  1369.       nc = 2;
  1370.       yvi[0] = yf - pstep;
  1371.       xvi[1] = xf - pstep;
  1372.       yvf[1] = yf - pstep;
  1373.       xi -= pstep;
  1374.       yi -= pstep;
  1375.       break;
  1376.       case 2:            /* down */
  1377.       yvi[0] = yf - pstep;
  1378.       yi -= pstep;
  1379.       break;
  1380.       case 3:
  1381.       nc = 2;
  1382.       yvi[0] = yf - pstep;
  1383.       xvf[1] = xi + pstep;
  1384.       yvf[1] = yf - pstep;
  1385.       xi += pstep;
  1386.       yi -= pstep;
  1387.       break;
  1388.       case 4:
  1389.       xvi[0] = xf - pstep;
  1390.       xi -= pstep;
  1391.       break;
  1392.       case 5:
  1393.       if (!last_center)
  1394.         {
  1395.         center_image(im, 2);
  1396.         xi = im->xi;
  1397.         yi = im->yi;
  1398.         }
  1399.       else
  1400.           nc = 0;
  1401.       break;
  1402.       case 6:
  1403.       xvf[0] = xi + pstep;
  1404.       xi += pstep;
  1405.       break;
  1406.       case 7:
  1407.       nc = 2;
  1408.       yvf[0] = yi + pstep;
  1409.       xvi[1] = xf - pstep;
  1410.       yvi[1] = yi + pstep;
  1411.       xi -= pstep;
  1412.       yi += pstep;
  1413.       break;
  1414.       case 8:
  1415.       yvf[0] = yi + pstep;
  1416.       yi += pstep;
  1417.       break;
  1418.       case 9:
  1419.       nc = 2;
  1420.       yvf[0] = yi + pstep;
  1421.       yvi[1] = yi + pstep;
  1422.       xvf[1] = xi + pstep;
  1423.       xi += pstep;
  1424.       yi += pstep;
  1425.       break;
  1426.       default:
  1427.       Bark("ImagePan", bugquit);    /* something is very wrong */
  1428.       clean_up();
  1429.       break;
  1430.       }
  1431.  
  1432.     if (nc)
  1433.       {
  1434.       xf = xi + im->w - 1;
  1435.       yf = yi + im->h - 1;
  1436.       if (xf < min_keep)
  1437.         {
  1438.         xf = min_keep;
  1439.         xi = xf - im->w + 1;
  1440.         }
  1441.  
  1442.       if (xi > win_w - min_keep)
  1443.         {
  1444.         xi = win_w - min_keep;
  1445.         xf = xi + im->w - 1;
  1446.         }
  1447.  
  1448.       if (yf < min_keep)
  1449.         {
  1450.         yf = min_keep;
  1451.         yi = yf - im->h + 1;
  1452.         }
  1453.  
  1454.       if (yi > win_h - min_keep)
  1455.         {
  1456.         yi = win_h - min_keep;
  1457.         yf = yi + im->h - 1;
  1458.         }
  1459.  
  1460.       im->xi = xi;
  1461.       im->xf = xf;
  1462.       im->yi = yi;
  1463.       im->yf = yf;
  1464.       positioning_image(im);
  1465.  
  1466.       if (!(xi < 0 && yi < 0 && xf > win_w && yf > win_w))
  1467.         {
  1468.         rect_clear(win_id, xvi[0], xvf[0], yvi[0], yvf[0]);
  1469.         if (nc > 1)
  1470.             rect_clear(win_id, xvi[1], xvf[1], yvi[1], yvf[1]);
  1471.         }
  1472.  
  1473.       display_auto = 1;
  1474.       im->io->display(im, -1, double_buf);
  1475.       display_auto = 0;
  1476.       }
  1477.  
  1478.     last_center = (x == 5);
  1479.  
  1480.     handle_wm_other(im);
  1481.     fl_qenter(KEYBD, 2);
  1482.  
  1483.     return 0;
  1484. }
  1485.  
  1486. /********************************************************************
  1487.  * Auto pan
  1488.  *******************************************************************/
  1489.  
  1490. #define PAN_CRIT    20        /* unviewable less than this is ignored */
  1491.  
  1492. void
  1493. auto_pan(IPTR im)
  1494. {
  1495.     int dist, dist1, dist2, pstep;
  1496.     int saveflag = always_clear;
  1497.  
  1498.     if ((im->w - PAN_CRIT) < win_w && (im->h - PAN_CRIT) < win_h)
  1499.     return;
  1500.  
  1501.     /* pan only if requestd or in slides show */
  1502.     if (always_pan == 0 || !(slideshow && always_pan == 1))
  1503.     return;
  1504.  
  1505.     msleep(500);        /* take a look at it         */
  1506.     display_auto = 1;        /* turn busy cursor off      */
  1507.     pstep = 4;            /* smaller steps looks nicer */
  1508.     always_clear = 0;        /* do not clear screen       */
  1509.  
  1510.     dist1 = Abs(im->xoff1);
  1511.     dist2 = Abs(im->xoff2);
  1512.  
  1513.     for (dist = dist1; dist > 0; dist -= pstep)
  1514.     image_pan(im, 6, pstep);/* move right */
  1515.  
  1516.     check_emergency();        /* service any Q event        */
  1517.  
  1518.     msleep(500);
  1519.  
  1520.     for (dist = dist1 + dist2; dist > 0; dist -= pstep)
  1521.     image_pan(im, 4, pstep);/* move left */
  1522.  
  1523.     check_emergency();
  1524.     msleep(500);
  1525.  
  1526.     for (dist = dist2; dist > 0; dist -= pstep)
  1527.     image_pan(im, 6, pstep);/* move right */
  1528.  
  1529.     check_emergency();
  1530.     msleep(500);
  1531.  
  1532.     /* image now is at about the same postion as before */
  1533.     dist1 = Abs(im->yoff1);
  1534.     dist2 = Abs(im->yoff2);
  1535.     for (dist = dist1; dist > 0; dist -= pstep)
  1536.     image_pan(im, 8, pstep);/* move up */
  1537.  
  1538.     check_emergency();
  1539.  
  1540.     for (dist = dist1 + dist2; dist > 0; dist -= pstep)
  1541.     image_pan(im, 2, pstep);/* move down */
  1542.  
  1543.     check_emergency();
  1544.     msleep(500);
  1545.  
  1546.     /* the corner still not seen, forget it */
  1547.     for (dist = dist2; dist > 0; dist -= 2 * pstep)
  1548.     image_pan(im, 8, 2 * pstep);    /* move up */
  1549.  
  1550.     /* center both dir */
  1551.     image_pan(im, 5, 10);
  1552.     display_auto = 0;
  1553.     always_clear = saveflag;
  1554. }
  1555.  
  1556. #if 0                /* No longer used **{* */
  1557. /*************************************************************
  1558.  * Rectcopy is similar to rectcopy except that it optionally
  1559.  * does raster move in core image. However, zooming is
  1560.  * not obeyed.
  1561.  ************************************************************/
  1562.  
  1563. static int rascp;
  1564.  
  1565. void
  1566. set_rectcp_ras(int y)
  1567. {
  1568.     rascp = y;
  1569. }
  1570.  
  1571. void
  1572. Rectcopy(int xi, int yi, int xf, int yf, int nx, int ny)
  1573. {
  1574.     IPTR im = imgptr;
  1575.     void *pp;
  1576.     Rect_t des, src;
  1577.     const Rect_t *ir, *uu;
  1578.  
  1579.     frontbuffer(1);
  1580.     rectcopy(xi, yi, xf, yf, nx, ny);
  1581.     frontbuffer(!double_buf);
  1582.  
  1583.     if (rascp)
  1584.       {
  1585.       int w, h;
  1586.  
  1587.       ir = img_rect(im);
  1588.  
  1589.       /* the src raster: clip to the image boundary */
  1590.       if (!(uu = union_rect(make_rect(xi, yi, xf - xi + 1, yf - yi + 1), ir)))
  1591.           return;
  1592.       copy_rect(&src, uu);
  1593.  
  1594.       /* find destination, taking into account of src clipping */
  1595.       nx += (src.x - xi);
  1596.       ny += (src.y - yi);
  1597.  
  1598.       copy_rect(&des, make_rect(nx, ny, src.w, src.h));
  1599.  
  1600.       /* clip to the image boundary */
  1601.       if (!(uu = union_rect(&des, ir)))
  1602.           return;
  1603.       copy_rect(&des, uu);
  1604.  
  1605.       w = Min(src.w, des.w);
  1606.       h = Min(src.h, des.h);
  1607.       des.w = src.w = w;
  1608.       des.h = src.h = h;
  1609.  
  1610.       if ((pp = get_subimage(im, src.x, src.y, src.w, src.h)))
  1611.         {
  1612.         put_subimage(im, pp, &des, 1);
  1613.         free_mat(pp);
  1614.         }
  1615.       }
  1616. }
  1617.  
  1618. #endif /* disabling Rectcopy } */
  1619.  
  1620. /**********************************************************
  1621.  * allow only certain number of bits in raster. This is necessary
  1622.  * because the raster might come from framebuffer read, which
  1623.  * is 12bits on most machines while CMAPBITS is less than 12
  1624.  ************************************************************/
  1625.  
  1626. void
  1627. do_ci_mask(register ci_t *ras, unsigned total,
  1628.        register unsigned int mask)
  1629. {
  1630.     register ci_t *rs = ras + total;
  1631.     int m = power_of_2(mask);
  1632.  
  1633.     /* need to make sure that mask is full bits */
  1634.     mask = (m > MAXCML ? MAXCML : m) - 1;
  1635.     for (; ras < rs; ras++)
  1636.     *ras &= mask;
  1637. }
  1638.  
  1639. /*
  1640.  * intended primarily to read the main screen
  1641.  */
  1642. int
  1643. read_screen(IPTR im, int x, int y, int w, int h)
  1644. {
  1645.     long owin = winget();
  1646.  
  1647.     M_info("ReadScr", "Performing screen read");
  1648.     im->xi = x;
  1649.     im->yi = y;
  1650.     im->xf = im->xi + w - 1;
  1651.     im->yf = im->yi + h - 1;
  1652.     im->w = w;
  1653.     im->h = h;
  1654.     set_current_window(win_id);
  1655.     reshapeviewport();
  1656.     im->ok = (img_get_rastermem(im) < 0) ? 0 :
  1657.     Rectread(im->xi, im->yi, im->xf, im->yf, im->raster) > 0;
  1658.     set_current_window(owin);
  1659.     return im->ok;
  1660. }
  1661.